home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
a_utils
/
_archvrs
/
mac
/
unzip101.sit
/
Source
/
unzip.c
< prev
next >
Wrap
Text File
|
1989-09-11
|
42KB
|
1,830 lines
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*
* UnZip - A ZIP file extract utility for ZIP files and ZIP ".EXE" files
* archived using PKZIP 1.01 or earlier. Recognizes and dearchives ╥stored╙,
* ╥shrunk╙, ╥reduced╙ and ╥imploded╙ files.
*
* VERSION: UnZip 1.01 ╤ Sep 10, 1989
*
* Translated into Lightspeed C v.3.02 and adapted for the Mac by A.P. Maika,
* (utilizing TransSkel 2.01 and TransDisplay 2.0 written by Paul DuBois)
*
* Dearchiving code for ╥extracting╙, ╥unshrinking╙, and ╥expanding╙ written
* in Turbo C v. 2.0 ⌐ Samuel H. Smith (version 1.2 of 03-15-89)
* Adapted for the Atari ST and CRC inline assembly code ⌐ Darin Wayrynen
*
* Dearchiving code for ╥exploding╙ derived from Turbo Pascal v. 5.0
* source ⌐ R.P. Byrne (version 2.0 of 07-31-89)
*/
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*
* Host operating system details
*/
#include <stdio.h>
#include <TransDisplay.h>
#include <strings.h>
#include <unix.h>
#include <Storage.h>
#define SEEK_CUR 1 (* lseek() modes *)
#define SEEK_END 2
#define SEEK_SET 0
#define HIGH_LOW 1
MenuHandle mFile,mOptions,mfilter,mstrip;
CursHandle c;
WindowRecord wprogressRec;
WindowPtr wlist,wprogress;
Point bloc = {40,40};
Rect prect;
SFReply SFzipfd;
FInfo ffinfo;
Boolean finishedflag;
Boolean stripLFflag=false;
Boolean wlistflag=false;
Boolean choosefileflag=false;
Boolean TEXTfilterflag=false;
char tstring[256],tfilename[256];
long zipoffset[100],progresscount,sizeblock;
int direntries,dindex,blockcount,numblocks;
typedef struct gifinfo
{
char gif_signature[6];
int screen_width;
int screen_height;
char color_resolution;
} gifinfo;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*
* dearchiving code Copyright 1989 Samuel H. Smith; All rights reserved
*
* Do not distribute modified versions without my permission.
* Do not remove or alter this notice or any other copyright notice.
* If you use this in your own program you must distribute source code.
* Do not use any of this in a commercial product.
*
*/
#define CODE_VERSION "UnZip: Zipfile Extract v1.2 of 03-15-89; (C) 1989 Samuel H. Smith"
typedef unsigned char byte; /* code assumes UNSIGNED bytes */
typedef long longint;
typedef unsigned word;
typedef char boolean;
#define STRSIZ 256
unsigned int in_size,out_size;
/* -------------------------------------------------------------------------- */
/*
* Zipfile layout declarations
*/
typedef longint signature_type;
#define LOCAL_FILE_HEADER_SIGNATURE 0x504B0304L
typedef struct local_file_header {
word version_needed_to_extract;
word general_purpose_bit_flag;
int compression_method;
int last_mod_file_time;
int last_mod_file_date;
longint crc32;
longint compressed_size;
longint uncompressed_size;
int filename_length;
int extra_field_length;
} local_file_header;
#define CENTRAL_FILE_HEADER_SIGNATURE 0x504B0102L
typedef struct central_directory_file_header {
word version_made_by;
word version_needed_to_extract;
word general_purpose_bit_flag;
word compression_method;
word last_mod_file_time;
word last_mod_file_date;
longint crc32;
longint compressed_size;
longint uncompressed_size;
word filename_length;
word extra_field_length;
word file_comment_length;
word disk_number_start;
word internal_file_attributes;
longint external_file_attributes;
longint relative_offset_local_header;
} central_directory_file_header;
#define END_CENTRAL_DIR_SIGNATURE 0x504B0506L
typedef struct end_central_dir_record {
word number_this_disk;
word number_disk_with_start_central_directory;
word total_entries_central_dir_on_this_disk;
word total_entries_central_dir;
longint size_central_directory;
longint offset_start_central_directory;
word zipfile_comment_length;
} end_central_dir_record;
/* -------------------------------------------------------------------------- */
/*
* input file variables
*
*/
#define INBUFSIZ 0x2000L
byte *inbuf; /* input file buffer - any size is legal */
byte *inptr;
int incnt;
unsigned bitbuf;
int bits_left;
boolean zipeof;
int zipfd;
local_file_header lrec;
/* -------------------------------------------------------------------------- */
/*
* output stream variables
*
*/
#define OUTBUFSIZ 0x6000L
byte *outbuf; /* buffer for rle look-back */
byte *outptr;
long outpos; /* absolute position in outfile */
int outcnt; /* current position in outbuf */
int outfd;
char filename[STRSIZ];
char extra[STRSIZ];
#define DLE 144
/* -------------------------------------------------------------------------- */
/*
* shrink/reduce working storage
*
*/
int factor;
byte followers[256][64];
byte Slen[256];
#define max_bits 13
#define init_bits 9
#define hsize 8192
#define first_ent 257
#define clear 256
int *Prefix_of;
byte *Suffix_of;
byte *Stack;
int codesize;
int maxcode;
int free_ent;
int maxcodemax;
int offset;
int sizex;
/* -------------------------------------------------------------------------- */
/* stuff needed for exploding */
#define LITERAL_TREE_ROOT 511
#define LIT_LAST_LEAF 255
#define DISTANCE_TREE_ROOT 127
#define DIST_LAST_LEAF 63
#define LENGTH_TREE_ROOT 127
#define LEN_LAST_LEAF 63
typedef struct SF_Node
{
int LChild;
int RChild;
} SF_Node;
SF_Node SF_Literal[LITERAL_TREE_ROOT + 1];
SF_Node SF_Distance[DISTANCE_TREE_ROOT + 1];;
SF_Node SF_Length[LENGTH_TREE_ROOT + 1];
typedef struct SF_BuildRec
{
int Len;
int Val;
int Code;
} SF_BuildRec;
int NextFreeLiteral;
int NextFreeLength;
int NextFreeDistance;
int NumOfTrees;
int MinMatchLen;
int DictSize;
/* -------------------------------------------------------------------------- */
void swap_bytes(wordp)
word *wordp;
/* convert intel style ╘short int╒ variable to host format */
{
char *charp = (char *) wordp;
char temp;
temp = charp[0];
charp[0] = charp[1];
charp[1] = temp;
}
/* -------------------------------------------------------------------------- */
void swap_lbytes(longp)
longint *longp;
/* convert intel style ╘long╒ variable to host format */
{
char *charp = (char *) longp;
char temp[4];
temp[3] = charp[0];
temp[2] = charp[1];
temp[1] = charp[2];
temp[0] = charp[3];
charp[0] = temp[0];
charp[1] = temp[1];
charp[2] = temp[2];
charp[3] = temp[3];
}
/* -------------------------------------------------------------------------- */
int FillBuffer()
/* fill input buffer if possible */
{
extern local_file_header lrec;
unsigned int readsize;
if (lrec.compressed_size <= 0 ) return (incnt = 0);
if (lrec.compressed_size > (long) in_size) readsize = in_size;
else readsize = (int) lrec.compressed_size;
incnt = read(zipfd, inbuf, readsize);
lrec.compressed_size -= incnt;
inptr = inbuf;
return (incnt--);
}
/* -------------------------------------------------------------------------- */
int ReadByte(x)
unsigned *x;
/* read a byte; return 8 if byte available, 0 if not */
{
/* counter for UpdateProgressWind */
if(sizeblock == ++progresscount)
{
progresscount = 0L;
UpdateProgressWind(numblocks,++blockcount);
}
if (incnt-- == 0)
if (FillBuffer() == 0)
return 0;
*x = *inptr++;
return 8;
}
/* -------------------------------------------------------------------------- */
static unsigned mask_bits[] =
{0, 0x0001, 0x0003, 0x0007, 0x000f,
0x001f, 0x003f, 0x007f, 0x00ff,
0x01ff, 0x03ff, 0x07ff, 0x0fff,
0x1fff, 0x3fff, 0x7fff, 0xffff
};
/* -------------------------------------------------------------------------- */
int FillBitBuffer(bits)
register int bits;
{
/* get the bits that are left and read the next word */
unsigned temp;
register int result = bitbuf;
int sbits = bits_left;
bits -= bits_left;
/* read next word of input */
bits_left = ReadByte(&bitbuf);
bits_left += ReadByte(&temp);
bitbuf |= (temp << 8);
if (bits_left == 0)
zipeof = 1;
/* get the remaining bits */
result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
bitbuf >>= bits;
bits_left -= bits;
return result;
}
/* -------------------------------------------------------------------------- */
#define READBIT(nbits,zdest) { if (nbits <= bits_left) { zdest = (int)(bitbuf & mask_bits[nbits]); bitbuf >>= nbits; bits_left -= nbits; } else zdest = FillBitBuffer(nbits);}
/*
* macro READBIT(nbits,zdest)
* {
* if (nbits <= bits_left) {
* zdest = (int)(bitbuf & mask_bits[nbits]);
* bitbuf >>= nbits;
* bits_left -= nbits;
* } else
* zdest = FillBitBuffer(nbits);
* }
*
*/
/* -------------------------------------------------------------------------- */
#include "crc32.h"
/* -------------------------------------------------------------------------- */
void FlushOutput()
/* flush contents of output buffer */
{
UpdateCRC(outbuf, outcnt);
write(outfd, outbuf, outcnt);
outpos = outpos + (long) outcnt;
outcnt = 0;
outptr = outbuf;
/* Monitor("",0,"",0,"outpos",outpos); */
}
/* -------------------------------------------------------------------------- */
#define OUTB(intc) { *outptr++=intc; if (++outcnt==out_size) FlushOutput(); }
/*
* macro OUTB(intc)
* {
* *outptr++=intc;
* if (++outcnt==out_size)
* FlushOutput();
* }
*
*/
/* -------------------------------------------------------------------------- */
void LoadFollowers()
{
register int x;
register int i;
for (x = 255; x >= 0; x--)
{
READBIT(6,Slen[x]);
for (i = 0; i < Slen[x]; i++)
{
READBIT(8,followers[x][i]);
}
}
}
/* -------------------------------------------------------------------------- */
/*
* The Reducing algorithm is actually a combination of two
* distinct algorithms. The first algorithm compresses repeated
* byte sequences, and the second algorithm takes the compressed
* stream from the first algorithm and applies a probabilistic
* compression method.
*/
int L_table[] = {0, 0x7f, 0x3f, 0x1f, 0x0f};
int D_shift[] = {0, 0x07, 0x06, 0x05, 0x04};
int D_mask[] = {0, 0x01, 0x03, 0x07, 0x0f};
int B_table[] = {8, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8};
/* -------------------------------------------------------------------------- */
void unReduce()
/* expand probablisticly reduced data */
{
register int lchar;
register int nchar;
int ExState;
register int V;
register int Len;
int ix,i,offset;
long op;
factor = lrec.compression_method - 1;
ExState = 0;
lchar = 0;
LoadFollowers();
while (((outpos + outcnt) < lrec.uncompressed_size) && (!zipeof))
{
if (Slen[lchar] == 0) READBIT(8,nchar) /* ; */
else
{
READBIT(1,nchar);
if (nchar != 0) READBIT(8,nchar) /* ; */
else
{
int follower;
int bitsneeded = B_table[Slen[lchar]];
READBIT(bitsneeded,follower);
nchar = followers[lchar][follower];
}
}
/* expand the resulting byte */
switch (ExState)
{
case 0:
if (nchar != DLE) OUTB(nchar) /* ; */
else
ExState = 1;
break;
case 1:
if (nchar != 0)
{
V = nchar;
Len = V & L_table[factor];
if (Len == L_table[factor]) ExState = 2;
else ExState = 3;
}
else
{
OUTB(DLE);
ExState = 0;
}
break;
case 2:
{
Len += nchar;
ExState = 3;
}
break;
case 3:
{
i = Len + 3;
offset = (((V >> D_shift[factor]) &
D_mask[factor]) << 8) + nchar + 1;
op = outpos + outcnt - offset;
/* special case- before start of file */
while ((op < 0L) && (i > 0))
{
OUTB(0);
op++;
i--;
}
/* normal copy of data from output buffer */
{
ix = (int) (op % out_size);
/* do a block memory copy if possible */
if ( ((ix +i) < out_size) && ((outcnt+i) < out_size) )
{
memcpy(outptr,&outbuf[ix],i);
outptr += i;
outcnt += i;
}
/* otherwise copy byte by byte */
else while (i--)
{
OUTB(outbuf[ix]);
if (++ix >= out_size) ix = 0;
}
}
ExState = 0;
}
break;
}
/* store character for next iteration */
lchar = nchar;
}
}
/* -------------------------------------------------------------------------- */
/*
* Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
* with partial clearing.
*
*/
void partial_clear()
{
extern int *Prefix_of;
register int pr;
register int cd;
/* mark all nodes as potentially unused */
for (cd = first_ent; cd < free_ent; cd++)
*(Prefix_of + cd) |= 0x8000;
/* unmark those that are used by other nodes */
for (cd = first_ent; cd < free_ent; cd++) {
pr = *(Prefix_of + cd) & 0x7fff; /* reference to another node? */
if (pr >= first_ent) /* flag node as referenced */
*(Prefix_of +pr) &= 0x7fff;
}
/* clear the ones that are still marked */
for (cd = first_ent; cd < free_ent; cd++)
if ((*(Prefix_of + cd) & 0x8000) != 0)
*(Prefix_of + cd) = -1;
/* find first cleared node as next free_ent */
cd = first_ent;
while ((cd < maxcodemax) && (*(Prefix_of + cd) != -1))
cd++;
free_ent = cd;
}
/* -------------------------------------------------------------------------- */
void unShrink()
{
#define GetCode(dest) READBIT(codesize,dest)
extern int *Prefix_of;
extern byte *Suffix_of;
extern local_file_header lrec;
extern byte *Stack;
register int code;
register int stackp;
int finchar;
int oldcode;
int incode;
void partial_clear();
/* decompress the file */
maxcodemax = 1 << max_bits;
codesize = init_bits;
maxcode = (1 << codesize) - 1;
free_ent = first_ent;
offset = 0;
sizex = 0;
for (code = maxcodemax; code > 255; code--)
*(Prefix_of + code) = -1;
for (code = 255; code >= 0; code--)
{
*(Prefix_of + code) = 0;
*(Suffix_of + code) = code;
}
GetCode(oldcode);
if (zipeof) return;
finchar = oldcode;
OUTB(finchar);
stackp = hsize;
while (!zipeof)
{
GetCode(code);
if (zipeof) return;
while (code == clear)
{
GetCode(code);
switch (code)
{
case 1:
{
codesize++;
if (codesize == max_bits)
maxcode = maxcodemax;
else
maxcode = (1 << codesize) - 1;
}
break;
case 2:
partial_clear();
break;
}
GetCode(code);
if (zipeof) return;
}
/* special case for KwKwK string */
incode = code;
if (*(Prefix_of + code) == -1)
{
*(Stack + --stackp) = finchar;
code = oldcode;
}
/* generate output characters in reverse order */
while (code >= first_ent)
{
*(Stack + --stackp) = *(Suffix_of + code);
code = *(Prefix_of + code);
}
finchar = *(Suffix_of + code);
*(Stack + --stackp) = finchar;
/* and put them out in forward order, block copy */
if ((hsize-stackp+outcnt) < out_size)
{
memcpy(outptr,Stack+stackp,hsize-stackp);
outptr += hsize-stackp;
outcnt += hsize-stackp;
stackp = hsize;
}
/* output byte by byte if we can╒t go by blocks */
else while (stackp < hsize)
OUTB(*(Stack + stackp++));
/* generate new entry */
code = free_ent;
if (code < maxcodemax)
{
*(Prefix_of + code) = oldcode;
*(Suffix_of + code) = finchar;
do
code++;
while ((code < maxcodemax) && (*(Prefix_of + code) != -1));
free_ent = code;
}
/* remember previous code */
oldcode = incode;
}
}
/* ------------------------------------------------------------------------- */
void get_string(len,s)
int len;
char *s;
{
read(zipfd, s, len);
s[len] = 0;
}
/* ------------------------------------------------------------------------- */
memcpy(to,from,count)
register char *to,*from;
register unsigned int count;
{
for(;count>0;--count,++to,++from)
*to=*from;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*
* Exploding code derived from Turbo Pascal v. 5.0 source ⌐ R.P. Byrne
* (version 2.0 ╤ July 31, 1989)
*
*/
/* -------------------------------------------------------------------------- */
Bad_SF_Tree()
{
CloseProgressWind();
DisplayString("\p -- bad Shannon-Fano decode tree -- file skipped\015");
}
/* -------------------------------------------------------------------------- */
Boolean Add_SF_SubTree(SF_TreePtr,SF_NextFreePtr,CurrNode,LastLeaf,SF_Code,SF_Len,SF_Val)
SF_Node (*SF_TreePtr)[];
int *SF_NextFreePtr;
int CurrNode;
int LastLeaf;
int SF_Code;
int SF_Len;
int SF_Val;
{
int i;
for (i=(SF_Len - 1); i>=1; i--)
{
if (CurrNode <= LastLeaf)
{
Bad_SF_Tree();
return(true);
}
if ((SF_Code >> i) & 0x0001)
{
if (-1 == (*SF_TreePtr)[CurrNode].RChild)
{
(*SF_TreePtr)[CurrNode].RChild = *SF_NextFreePtr;
(*SF_NextFreePtr)--;
}
CurrNode = (*SF_TreePtr)[CurrNode].RChild;
}
else
{
if (-1 == (*SF_TreePtr)[CurrNode].LChild)
{
(*SF_TreePtr)[CurrNode].LChild = *SF_NextFreePtr;
(*SF_NextFreePtr)--;
}
CurrNode = (*SF_TreePtr)[CurrNode].LChild;
}
}
if (SF_Code & 0x0001)
{
if (-1 != (*SF_TreePtr)[CurrNode].RChild)
{
Bad_SF_Tree();
return(true);
}
else (*SF_TreePtr)[CurrNode].RChild = SF_Val;
}
else
{
if (-1 != (*SF_TreePtr)[CurrNode].LChild)
{
Bad_SF_Tree();
return(true);
}
else (*SF_TreePtr)[CurrNode].LChild = SF_Val;
}
return (false);
}
/* -------------------------------------------------------------------------- */
Boolean Construct_SF_Tree(SF_TreePtr,SF_NextFreePtr,treesize,LastLeaf)
SF_Node (*SF_TreePtr)[];
int *SF_NextFreePtr;
int treesize;
int LastLeaf;
{
SF_BuildRec SF_Build[256];
SF_BuildRec tempnode;
int OneByte;
char CodeLen;
char CodeCount;
int SF_Table_Codes;
int SF_Build_Idx;
int BuildCount;
unsigned int Code;
unsigned int CodeIncrement;
int LastBitLength;
int i,j;
Boolean swapflag=true;
SF_Build_Idx = 0;
BuildCount = 0;
if(0 == ReadByte(&SF_Table_Codes))
{
DisplayString("\p -- unexpected end of file -- file skipped");
return(true);
}
for (i=0; i<=SF_Table_Codes; i++)
{
if(0 == ReadByte(&OneByte))
{
DisplayString("\p -- unexpected end of file -- file skipped");
return(true);
}
CodeLen = (OneByte & 0x000F) + 1;
CodeCount = (OneByte >> 4) & 0x000F;
for (j=0; j<=CodeCount; j++)
{
SF_Build[SF_Build_Idx].Len = CodeLen;
SF_Build[SF_Build_Idx].Val = SF_Build_Idx;
SF_Build_Idx++;
}
}
BuildCount = SF_Build_Idx - 1;
/* bubble sort of tree leaves */
while(swapflag)
{
swapflag = false;
for (i=0; i<BuildCount; i++)
{
if( (SF_Build[i].Len > SF_Build[i+1].Len) ||
( (SF_Build[i].Len == SF_Build[i+1].Len) &&
(SF_Build[i].Val > SF_Build[i+1].Val) ) )
{
tempnode.Len = SF_Build[i].Len;
tempnode.Val = SF_Build[i].Val;
SF_Build[i].Len = SF_Build[i+1].Len;
SF_Build[i].Val = SF_Build[i+1].Val;
SF_Build[i+1].Len = tempnode.Len;
SF_Build[i+1].Val = tempnode.Val;
swapflag = true;
}
}
}
Code = 0;
CodeIncrement = 0;
LastBitLength = 0;
for (i=BuildCount; i>=0; i--)
{
Code = Code + CodeIncrement;
if(SF_Build[i].Len != LastBitLength)
{
LastBitLength = SF_Build[i].Len;
CodeIncrement = 1 << (16 - LastBitLength);
}
SF_Build[i].Code = Code >> (16 - SF_Build[i].Len);
/* sprintf(tstring,"\r%3d %3d %3d %4X",i,SF_Build[i].Len,SF_Build[i].Val,SF_Build[i].Code);
DisplayString(CtoPstr(tstring)); */
if(Add_SF_SubTree( SF_TreePtr,
SF_NextFreePtr,
treesize,
LastLeaf,
SF_Build[i].Code,
SF_Build[i].Len,
SF_Build[i].Val )) return (true);
}
/* for (i=0;i<=treesize;i++)
fprintf(sftrees,"\r%3d %3d %3d",i,(*SF_TreePtr)[i].LChild,(*SF_TreePtr)[i].RChild);
fprintf(sftrees,"\r\r"); */
return (false);
}
/* -------------------------------------------------------------------------- */
Boolean Init_Explode()
{
int i;
DictSize = (((lrec.general_purpose_bit_flag >> 1) & 0x01) * 4096) + 4096;
NumOfTrees = ((lrec.general_purpose_bit_flag >> 2) & 0x01) + 2;
MinMatchLen = NumOfTrees;
for (i=0; i<=LENGTH_TREE_ROOT; i++)
{
SF_Length[i].LChild = -1;
SF_Length[i].RChild = -1;
}
NextFreeLength = LENGTH_TREE_ROOT - 1;
for (i=0; i<=DISTANCE_TREE_ROOT; i++)
{
SF_Distance[i].LChild = -1;
SF_Distance[i].RChild = -1;
}
NextFreeDistance = DISTANCE_TREE_ROOT - 1;
if(3==NumOfTrees)
{
for (i=0; i<=LITERAL_TREE_ROOT; i++)
{
SF_Literal[i].LChild = -1;
SF_Literal[i].RChild = -1;
}
NextFreeLiteral = LITERAL_TREE_ROOT - 1;
if(Construct_SF_Tree(&SF_Literal,&NextFreeLiteral,LITERAL_TREE_ROOT,LIT_LAST_LEAF)) return(true);
}
if(Construct_SF_Tree(&SF_Length,&NextFreeLength,LENGTH_TREE_ROOT,LEN_LAST_LEAF)) return(true);
if(Construct_SF_Tree(&SF_Distance,&NextFreeDistance,DISTANCE_TREE_ROOT,DIST_LAST_LEAF)) return(true);
return (false);
}
/* -------------------------------------------------------------------------- */
Boolean Decode_SF_Data(SF_TreePtr,CurrNode,LastLeaf,OutputPtr)
SF_Node (*SF_TreePtr)[];
int CurrNode;
int LastLeaf;
int *OutputPtr;
{
int OneBit;
while (CurrNode > LastLeaf)
{
READBIT(1,OneBit);
if (OneBit)
{
if (-1 == (*SF_TreePtr)[CurrNode].RChild)
{
Bad_SF_Tree();
return(true);
}
else CurrNode = (*SF_TreePtr)[CurrNode].RChild;
}
else
{
if (-1 == (*SF_TreePtr)[CurrNode].LChild)
{
Bad_SF_Tree();
return(true);
}
else CurrNode = (*SF_TreePtr)[CurrNode].LChild;
}
}
*OutputPtr = CurrNode;
return (false);
}
/* -------------------------------------------------------------------------- */
Explode()
{
extern byte *Stack;
int State;
int StackIdx;
int StackStart;
int Length;
int DistVal;
int Distance;
int Literal;
int OneByte;
int i;
Boolean BigDictflag;
Boolean LiteralTreeflag;
if(Init_Explode()) return;
State = 0;
StackIdx = 0;
for (i=0; i<=hsize+1; i++) Stack[i] = 0;
BigDictflag = (8192 == DictSize);
LiteralTreeflag = (3 == NumOfTrees);
while ((!zipeof) && ((outpos + outcnt) < lrec.uncompressed_size))
{
READBIT(1,OneByte);
if (OneByte)
{
if(LiteralTreeflag)
{
if(Decode_SF_Data(&SF_Literal,LITERAL_TREE_ROOT,LIT_LAST_LEAF,&Literal)) return;
}
else READBIT(8,Literal);
OUTB(Literal);
Stack[StackIdx] = (char) Literal;
if(DictSize == ++StackIdx) StackIdx = 0;
}
else
{
if (BigDictflag)
{
READBIT(7,Distance);
if(Decode_SF_Data(&SF_Distance,DISTANCE_TREE_ROOT,DIST_LAST_LEAF,&DistVal)) return;
Distance = (Distance | (DistVal << 7)) & 0x1FFF;
}
else
{
READBIT(6,Distance);
if(Decode_SF_Data(&SF_Distance,DISTANCE_TREE_ROOT,DIST_LAST_LEAF,&DistVal)) return;
Distance = (Distance | (DistVal << 6)) & 0x0FFF;
}
if(Decode_SF_Data(&SF_Length,LENGTH_TREE_ROOT,LEN_LAST_LEAF,&Length)) return;
if (63 == Length)
{
READBIT(8,i);
Length = Length + i;
}
Length = Length + MinMatchLen;
StackStart = StackIdx - (Distance + 1);
if(0 > StackStart) StackStart = StackStart + DictSize;
while (Length-- > 0)
{
OUTB(Stack[StackStart]);
Stack[StackIdx] = Stack[StackStart];
if(DictSize == ++StackIdx) StackIdx = 0;
if(DictSize == ++StackStart) StackStart = 0;
}
}
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
OSErr freeSpaceOnVol(vRef,pfreeBytes)
int vRef;
long *pfreeBytes;
{
HVolumeParam HPB;
OSErr err;
HPB.ioNamePtr = 0L;
HPB.ioVRefNum = vRef;
HPB.ioVolIndex = 0;
err = PBHGetVInfo(&HPB,false);
if(err==noErr) *pfreeBytes = (long) HPB.ioVFrBlk * HPB.ioVAlBlkSiz;
else *pfreeBytes = 0L;
return(err);
}
/* ------------------------------------------------------------------------- */
Monitor(s1,v1,s2,v2,s3,v3)
/* debugging routine to monitor variables */
char s1[32],s2[32],s3[32];
int v1,v2;
long v3;
{
char ts1[60],ts2[60],ts3[60];
sprintf(ts1,"%10d %s",v1,s1);
sprintf(ts2,"%10d %s",v2,s2);
sprintf(ts3,"%10ld %s",v3,s3);
ParamText(CtoPstr(ts1),CtoPstr(ts2),CtoPstr(ts3),"\p");
Alert(103,nil);
}
/* -------------------------------------------------------------------------- */
InitProgressWind(dearchivingtype)
char *dearchivingtype;
{
int width;
wprogress = GetNewWindow(102,&wprogressRec,-1L);
SetPort(wprogress);
sprintf(tstring,"%s : %s %ld \304> %ld bytes",
dearchivingtype,
filename,
lrec.compressed_size,
lrec.uncompressed_size);
TextFont(150);
TextSize(9);
TextFace(bold);
width = StringWidth(CtoPstr(tstring));
MoveTo(((416-width)/2),15);
DrawString(tstring);
SetRect(&prect,38,22,380,40);
FrameRect(&prect);
numblocks = 20;
sizeblock = lrec.compressed_size/20L;
if(50000L > lrec.compressed_size)
{
sizeblock = lrec.compressed_size/10L;
numblocks = 10;
}
if(10000L > lrec.compressed_size)
{
sizeblock = lrec.compressed_size/4L;
numblocks = 4;
}
if( 2000L > lrec.compressed_size)
{
sizeblock = lrec.compressed_size/2L;
numblocks = 2;
}
progresscount = 0L;
blockcount = 0;
PenPat(gray);
}
/* -------------------------------------------------------------------------- */
UpdateProgressWind(numblocks,blockcount)
int numblocks,blockcount;
{
Rect r;
/* if(blockcount > numblocks) blockcount = numblocks; */
SetRect(&r,(39+(blockcount-1)*340/numblocks),23,(39+blockcount*340/numblocks),39);
PaintRect(&r);
}
/* -------------------------------------------------------------------------- */
CloseProgressWind()
{
CloseWindow(wprogress);
}
/* -------------------------------------------------------------------------- */
void set_file_time()
{
HFileInfo FiInfo;
unsigned char tfname[256];
OSErr result;
DateTimeRec dtr;
long seconds;
strcpy(tstring,filename);
CtoPstr(tstring);
strcpy(tfname,tstring);
FiInfo.ioNamePtr = tfname;
FiInfo.ioVRefNum = 0;
FiInfo.ioFVersNum = 0;
FiInfo.ioFDirIndex = 0;
result = PBGetFInfo(&FiInfo,false);
dtr.day = lrec.last_mod_file_date & 0x1F;
dtr.month = (lrec.last_mod_file_date >> 5) & 0x0F;
dtr.year = ((lrec.last_mod_file_date >> 9) & 0x7F) + 1980;
dtr.second = 0;
dtr.minute = (lrec.last_mod_file_time >> 5) & 0x3F;
dtr.hour = (lrec.last_mod_file_time >>11) & 0x1F;
dtr.second = 2*(lrec.last_mod_file_time & 0x1F);
Date2Secs(&dtr,&seconds);
FiInfo.ioFlCrDat = seconds;
FiInfo.ioFlMdDat = seconds;
result = PBSetFInfo(&FiInfo,false);
}
/* -------------------------------------------------------------------------- */
int create_output_file()
/* return non-0 if creat failed */
{
extern local_file_header lrec;
char temp[256];
long freebytes;
int filerr;
freeSpaceOnVol(SFzipfd.vRefNum,&freebytes);
if(lrec.uncompressed_size > freebytes)
{
sprintf(tstring,"***********: %-12s -- no space on volume -- file skipped",filename);
DisplayString(CtoPstr(tstring));
return(1);
}
outfd = creat(filename, O_CREAT | O_RDWR | O_BINARY);
if (outfd == EOF)
{
sprintf(tstring,"***********: %-12s -- can╒t create output file -- file skipped",filename);
DisplayString(CtoPstr(tstring));
return(1);
}
strcpy(tstring,filename);
GetFInfo(CtoPstr(tstring),NULL,&ffinfo);
ffinfo.fdCreator = 'pZIP';
ffinfo.fdType = 'TEXT';
if((0L<zipoffset[dindex]) && (4!=stcpm(filename,".GIF",temp)) && (4!=stcpm(filename,".gif",temp))) ffinfo.fdType='pBIN';
SetFInfo(tstring,NULL,&ffinfo);
/* write a single byte at EOF to pre-allocate the file */
lseek(outfd, lrec.uncompressed_size-1L, SEEK_SET);
filerr = write(outfd, "?", 1);
lseek(outfd, 0L, SEEK_SET);
return(0);
}
/* ------------------------------------------------------------------------- */
extract_member()
{
extern local_file_header lrec;
gifinfo gi;
char colors,temp[256];
int ncolors;
long freebytes;
unsigned b;
FILE *in,*out;
int ch;
bits_left = 0;
bitbuf = 0;
incnt = 0;
outpos = 0L;
outcnt = 0;
outptr = outbuf;
zipeof = 0;
crc32val = 0xFFFFFFFFL;
/* create the output file with READ and WRITE permissions */
if(7>lrec.compression_method)
{
if (create_output_file())
{
DisplayLn();
SysBeep(1);
return(1);
}
}
switch (lrec.compression_method)
{
case 0: /* stored */
{
sprintf(tstring," Extracting: %-12s ", filename);
DisplayString(CtoPstr(tstring));
InitProgressWind("Extracting");
while (ReadByte(&b)) OUTB(b);
CloseProgressWind();
}
break;
case 1:
{
sprintf(tstring,"UnShrinking: %-12s ", filename);
DisplayString(CtoPstr(tstring));
InitProgressWind("UnShrinking");
unShrink();
CloseProgressWind();
}
break;
case 2:
case 3:
case 4:
case 5:
{
sprintf(tstring," Expanding: %-12s ",filename);
DisplayString(CtoPstr(tstring));
InitProgressWind("Expanding");
unReduce();
CloseProgressWind();
}
break;
case 6:
{
sprintf(tstring," Exploding: %-12s ",filename);
DisplayString(CtoPstr(tstring));
InitProgressWind("Exploding");
Explode();
CloseProgressWind();
}
break;
default:
{
sprintf(tstring," : %-12s -- unknown compression method -- file skipped\015",filename);
DisplayString(CtoPstr(tstring));
}
}
if(6<lrec.compression_method) return;
/* write the last partial buffer, if any */
if (outcnt > 0)
{
UpdateCRC(outbuf, outcnt);
write(outfd, outbuf, outcnt);
}
crc32val = -1 - crc32val;
if (crc32val != lrec.crc32)
{
sprintf(tstring," -- Bad CRC %08lX (should be %08lX)", lrec.crc32, crc32val);
DisplayString(CtoPstr(tstring));
}
else DisplayString("\p -- successful");
/* if file ended in '.GIF' or '.gif' display additional GIF file info */
if((4==stcpm(filename,".GIF",temp)) || (4==stcpm(filename,".gif",temp)))
{
lseek(outfd,0L,0L);
read(outfd,&gi,sizeof(gifinfo));
swap_bytes(&gi.screen_width);
swap_bytes(&gi.screen_height);
colors = gi.color_resolution & '\007';
ncolors = 1 << (1+(int) colors);
sprintf(tstring,"\015 -- GIF file: %dx%d %d colors",gi.screen_width,gi.screen_height,ncolors);
DisplayString(CtoPstr(tstring));
}
close(outfd);
/* strip linefeeds from text files if stripLFflag = true */
if (stripLFflag && (0>zipoffset[dindex]))
{
freeSpaceOnVol(SFzipfd.vRefNum,&freebytes);
if(lrec.uncompressed_size > freebytes)
{
DisplayString("\p\015 -- no space on volume for LF stripped file");
}
else
{
DisplayString("\p\015 -- stripping LF's ");
in = fopen(filename,"rb");
out = fopen("pZIPtemp01","wb");
if (out != NULL)
{
strcpy(tstring,"pZIPtemp01");
GetFInfo(CtoPstr(tstring),NULL,&ffinfo);
ffinfo.fdCreator = 'pZIP';
ffinfo.fdType = 'TEXT';
SetFInfo(tstring,NULL,&ffinfo);
while ((ch=getc(in)) != EOF) if('\012' != ch) putc(ch,out);
fclose(in);
fclose(out);
remove(filename);
rename("pZIPtemp01",filename);
DisplayString("\p -- successful");
}
else
{
DisplayString("\p\015 -- error opening LF stripped file -- skipped");
}
}
}
/* set output file date and time */
set_file_time();
DisplayLn();
}
/* ------------------------------------------------------------------------- */
void process_local_file_header()
{
extern local_file_header lrec;
char temp[256];
read(zipfd, &lrec, sizeof(lrec));
swap_bytes(&lrec.filename_length);
swap_bytes(&lrec.extra_field_length);
swap_lbytes(&lrec.compressed_size);
swap_lbytes(&lrec.uncompressed_size);
swap_bytes(&lrec.last_mod_file_time);
swap_bytes(&lrec.last_mod_file_date);
swap_bytes(&lrec.compression_method);
swap_bytes(&lrec.general_purpose_bit_flag);
swap_lbytes(&lrec.crc32);
get_string(lrec.filename_length, filename);
get_string(lrec.extra_field_length, extra);
if(TEXTfilterflag && (0L<zipoffset[dindex]) && (4!=stcpm(filename,".GIF",temp)) && (4!=stcpm(filename,".gif",temp))) return;
if (choosefileflag)
{
strcpy(tstring,"Dearchive ╥");
strcat(tstring,filename);
strcat(tstring,"╙?");
ParamText(CtoPstr(tstring),"\p","\p","\p");
InitCursor();
if(1==Alert (102,nil))
{
c = GetCursor(watchCursor);
SetCursor(*c);
extract_member();
}
}
else extract_member();
}
/* -------------------------------------------------------------------------- */
long process_central_file_header()
{
central_directory_file_header rec;
char filename[STRSIZ];
char extra[STRSIZ];
char comment[STRSIZ];
static char *method[8]={" Stored"," Shrunk"," Reduced1"," Reduced2"," Reduced3"," Reduced4"," Imploded"," Unknown"};
static char *ny[2]={" no","yes"};
static char *mo[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
long offset;
int day,month,year,hour,minute,second;
read(zipfd, &rec, sizeof(rec));
swap_bytes(&rec.compression_method);
swap_lbytes(&rec.compressed_size);
swap_lbytes(&rec.uncompressed_size);
swap_bytes(&rec.last_mod_file_time);
swap_bytes(&rec.last_mod_file_date);
swap_lbytes(&rec.crc32);
swap_bytes(&rec.internal_file_attributes);
swap_bytes(&rec.filename_length);
swap_bytes(&rec.extra_field_length);
swap_bytes(&rec.file_comment_length);
swap_lbytes(&rec.relative_offset_local_header);
get_string(rec.filename_length,filename);
get_string(rec.extra_field_length,extra);
get_string(rec.file_comment_length,comment);
if(6<rec.compression_method) rec.compression_method = 7;
day = rec.last_mod_file_date & 0x1F;
month = (rec.last_mod_file_date >> 5) & 0x0F;
year = ((rec.last_mod_file_date >> 9) & 0x7F) + 80;
hour = (rec.last_mod_file_time >>11) & 0x1F;
minute = (rec.last_mod_file_time >> 5) & 0x3F;
second = 2*(rec.last_mod_file_time & 0x1F);
sprintf(tstring,"%-12s%s%10ld %10ld%4d-%3s-%2d %02d:%02d:%02d %08lX %3s\015",
filename,
method[rec.compression_method],
rec.compressed_size,
rec.uncompressed_size,
day,
mo[month-1],
year,
hour,
minute,
second,
rec.crc32,
ny[rec.internal_file_attributes]);
DisplayString(CtoPstr(tstring));
offset = 1L + rec.relative_offset_local_header;
if (1==rec.internal_file_attributes) offset = -offset;
return(offset);
}
/* ------------------------------------------------------------------------- */
int process_end_central_dir()
{
end_central_dir_record rec;
char comment[2048];
Rect drect;
lseek(zipfd,5L,1);
read(zipfd, &rec, sizeof(rec));
swap_bytes(&rec.total_entries_central_dir);
swap_lbytes(&rec.offset_start_central_directory);
swap_bytes(&rec.zipfile_comment_length);
get_string(rec.zipfile_comment_length,comment);
wlistflag = true;
wlist = GetNewDWindow(101,-1L);
SetWTitle(wlist,&SFzipfd.fName);
SetDWindowStyle(wlist,150,9,1,0);
/* rec.zipfile_comment_length = stripLFfn(rec.zipfile_comment_length,comment); */
DisplayText(comment,(long) rec.zipfile_comment_length);
lseek(zipfd,rec.offset_start_central_directory,0);
return(rec.total_entries_central_dir);
}
/* ------------------------------------------------------------------------- */
long labs(x)
long x;
{
long y;
y = x;
if(0L>y) y = -y;
return(y);
}
/* ------------------------------------------------------------------------- */
void process_headers()
{
longint sig;
if(!wlistflag)
{
SysBeep(1);
strcpy(tstring,"\015Cannot extract until ZIP file opened!");
ParamText(CtoPstr(tstring),"\p","\p","\p");
HiliteMenu(nil);
(void) StopAlert(101,nil);
return;
}
if(finishedflag)
{
SysBeep(1);
strcpy(tstring,"\015ZIP file extraction completed for this file!");
ParamText(CtoPstr(tstring),"\p","\p","\p");
HiliteMenu(nil);
(void) StopAlert(101,nil);
return;
}
c = GetCursor(watchCursor);
SetCursor(*c);
for (dindex=0;dindex<direntries;dindex++)
{
lseek(zipfd,labs(zipoffset[dindex])-1,0);
read(zipfd, &sig, sizeof(sig));
if (sig != LOCAL_FILE_HEADER_SIGNATURE)
{
DisplayString("\pBad ZIP file local header signature--file skipped\015");
}
else process_local_file_header();
}
InitCursor();
close(zipfd);
finishedflag = true;
Delay(20L,sig);
SysBeep(1);
Delay(5L,sig);
SysBeep(1);
strcpy(tstring,"\015ZIP file extraction completed!");
ParamText(CtoPstr(tstring),"\p","\p","\p");
HiliteMenu(nil);
(void) NoteAlert (101,nil);
}
/* ------------------------------------------------------------------------- */
AllocateBuffers()
{
int buffer_fail = 0;
extern int *Prefix_of;
extern byte *Suffix_of;
extern byte *Stack;
int i;
Prefix_of = calloc(hsize+1,2);
Suffix_of = calloc(hsize+1,1);
Stack = calloc(hsize+1,1);
/* allocate i/o buffers */
inbuf = (byte *) (mlalloc(INBUFSIZ));
outbuf = (byte *) (mlalloc(OUTBUFSIZ));
in_size = INBUFSIZ;
out_size = OUTBUFSIZ;
if ((inbuf == NULL) || (outbuf == NULL))
{
ParamText("\pInsufficient memory to allocate buffers!","\p","\p","\p");
(void) StopAlert (101,nil);
SkelWhoa();
}
}
/* ------------------------------------------------------------------------- */
aboutUnZip()
{
(void) Alert(100,nil);
}
/* ------------------------------------------------------------------------- */
setLFflag()
{
if (!stripLFflag)
{
stripLFflag = true;
CheckItem(mOptions,3,true);
mstrip = NewMenu(5,"\p*Strip LF on*");
SkelMenu(mstrip,nil,nil);
}
else
{
stripLFflag = false;
CheckItem(mOptions,3,false);
mstrip = NewMenu(5,"\p");
SkelMenu(mstrip,nil,nil);
}
}
/* ------------------------------------------------------------------------- */
setTEXTfilterflag()
{
if (!TEXTfilterflag)
{
TEXTfilterflag = true;
CheckItem(mOptions,4,true);
mfilter = NewMenu(4,"\p*.GIF & TEXT filter*");
SkelMenu(mfilter,nil,nil);
}
else
{
TEXTfilterflag = false;
CheckItem(mOptions,4,false);
mfilter = NewMenu(4,"\p");
SkelMenu(mfilter,nil,nil);
}
}
/* ------------------------------------------------------------------------- */
setchoosefileflag()
{
if (!choosefileflag)
{
choosefileflag = true;
CheckItem(mOptions,5,true);
}
else
{
choosefileflag = false;
CheckItem(mOptions,5,false);
}
}
/* ------------------------------------------------------------------------- */
openfile()
{
extern int direntries;
long sig;
long flength;
long temp;
if(wlistflag)
{
if (!finishedflag) close(zipfd);
SkelRmveWind(wlist);
wlistflag = false;
}
finishedflag = false;
SFGetFile(bloc,"\p",nil,-1,nil,nil,&SFzipfd);
if(!SFzipfd.good) return;
else SetVol("\p",SFzipfd.vRefNum);
c = GetCursor(watchCursor);
SetCursor(*c);
stccpy(tstring,&SFzipfd.fName,64);
zipfd = open(PtoCstr(tstring), O_RDONLY | O_BINARY);
flength = lseek(zipfd,-22L,2);
while (1)
{
read(zipfd,&sig,sizeof(sig));
temp = lseek(zipfd,-5L,1);
if( (45L>=temp) || (1024L<=(flength-temp)) )
{
/* not a ZIP file alert */
stccpy(tstring,&SFzipfd.fName,64);
PtoCstr(tstring);
strcat(tstring,"\015\015Not a ZIP file!");
ParamText(CtoPstr(tstring),"\p","\p","\p");
InitCursor();
SysBeep(1);
HiliteMenu(nil);
(void) StopAlert (101,nil);
close(zipfd);
return;
}
if (sig == END_CENTRAL_DIR_SIGNATURE)
{
direntries = process_end_central_dir();
break;
}
}
DisplayString("\p\015\015File Name Method Size Now Full Size Date Time CRC Text\015");
DisplayString("\p--------- -------- -------- --------- --------- -------- -------- ----\015");
for (dindex=0;dindex<direntries;dindex++)
{
read(zipfd, &sig, sizeof(sig));
if (sig == CENTRAL_FILE_HEADER_SIGNATURE) zipoffset[dindex]=process_central_file_header();
}
DisplayLn();
InitCursor();
SysBeep(6);
SetDWindowPos(wlist,0);
ShowWindow(wlist);
}
/* ------------------------------------------------------------------------- */
DoFileMenu(item)
int item;
{
switch(item)
{
case 1: openfile(); break;
case 2: {
cfree(Prefix_of);
cfree(Suffix_of);
cfree(Stack);
cfree(inbuf);
cfree(outbuf);
SkelWhoa();
break;
}
}
}
/* ------------------------------------------------------------------------- */
DoOptionsMenu(item)
int item;
{
switch(item)
{
case 1: process_headers(); break;
case 2: break;
case 3: setLFflag(); break;
case 4: setTEXTfilterflag();break;
case 5: setchoosefileflag(); break;
}
}
/* ------------------------------------------------------------------------- */
void main()
{
SkelInit(6,nil);
SkelApple("\pAbout UnZip 1.01╔",aboutUnZip);
mFile = GetMenu(101);
(void) SkelMenu(mFile,DoFileMenu,nil,false);
mOptions = GetMenu(102);
(void) SkelMenu(mOptions,DoOptionsMenu,nil,true);
AllocateBuffers();
SkelMain();
SkelClobber();
}